package com.ck.print.demo.demo;


import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import cn.hutool.json.JSONUtil;

@Slf4j
public class MyWebSocketClient extends WebSocketClient {
    // 重连相关配置
    private static final int MAX_RETRY_COUNT = 1000; // 最大重试次数
    private static final int INITIAL_RECONNECT_DELAY = 1; // 初始重连延迟（秒）
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    private final AtomicBoolean isReconnecting = new AtomicBoolean(false);
    private int retryCount = 0;

    public MyWebSocketClient(String serverUri) throws URISyntaxException {
        super(new URI(serverUri));
    }

    /**
     * call: callName,
     *                         promise: { resolve: resolve, reject: reject },
     *                         params: params,
     *                         signature: signature,
     *                         timestamp: signingTimestamp
     * @param handshakedata The handshake of the websocket instance
     */
    @Override
    public void onOpen(ServerHandshake handshakedata) {
        log.info("连接成功！状态码：" + handshakedata.getHttpStatus());
        retryCount = 0; // 重置重试计数
        // 连接成功后可发送初始化消息
        Map<String, String> data = new HashMap<>();
        data.put("call", "networking.devices");
        data.put("timestamp", System.currentTimeMillis() + "");
        data.put("signature", null);
        data.put("params", null);

        send(JSONUtil.toJsonStr(data));
    }

    // 收到消息时调用
    @Override
    public void onMessage(String message) {
        log.info("收到消息：" + message);
        // 处理业务逻辑（例如解析JSON、更新本地数据等）
        handleMessage(message);
    }

    // 连接关闭时调用
    @Override
    public void onClose(int code, String reason, boolean remote) {
        log.info("连接关闭：code=" + code + ", reason=" + reason);
        // 触发重连（远程主动关闭或本地断连都尝试重连）
        scheduleReconnect();
    }

    // 发生错误时调用
    @Override
    public void onError(Exception ex) {
        log.info("连接错误：{}", ex.getMessage());
        // 错误导致的断连也触发重连
        scheduleReconnect();
    }

    // 业务消息处理逻辑
    private void handleMessage(String message) {
        // 根据实际业务需求处理消息
        try {
            // 示例：模拟消息处理失败的场景
            if (message.contains("error")) {
                throw new RuntimeException("消息处理失败，需要重连");
            }
        } catch (Exception e) {
            log.error("消息处理异常，触发重连：{}", e.getMessage());
            close(); // 主动关闭连接，触发重连
        }
    }

    // 调度重连（带指数退避策略）
    private void scheduleReconnect() {
        // 防止并发重连
        if (isReconnecting.compareAndSet(false, true)) {
            if (retryCount >= MAX_RETRY_COUNT) {
                log.error("已达最大重试次数（" + MAX_RETRY_COUNT + "），停止重连");
                isReconnecting.set(false);
                return;
            }

            // 指数退避：延迟时间 = 初始延迟 * 2^重试次数（最多延迟30秒）
            long delay = (long) Math.min(
                    INITIAL_RECONNECT_DELAY * Math.pow(2, retryCount),
                    30 // 最大延迟30秒
            );

            log.info("计划在 " + delay + " 秒后重连（第 " + (retryCount + 1) + " 次）");
            scheduler.schedule(() -> {
                try {
                    retryCount++;
                    close();
                    reconnect(); // 执行重连
                    isReconnecting.set(false);
                } catch (Exception e) {
                    isReconnecting.set(false);
                    scheduleReconnect();
                } finally {

                }
            }, delay, TimeUnit.SECONDS);
        }
    }

    // 关闭资源（程序退出时调用）
    public void shutdown() {
        scheduler.shutdown();
        close();
    }

    // 测试客户端
    public static void main(String[] args) throws URISyntaxException, InterruptedException {
        MyWebSocketClient client = new MyWebSocketClient("ws://localhost:8182");
        client.connect(); // 启动连接

        // 模拟发送消息
//        Thread.sleep(1000);
//        Map<String,String> data = new HashMap<>();
//        data.put("name","张三");
//        client.send(JSONUtil.toJsonStr(data));

        // 保持客户端运行（实际项目中根据需求调整）
        Runtime.getRuntime().addShutdownHook(new Thread(client::shutdown));
    }
}
